﻿#pragma once
#include"Socket.h"
#include"Process.h"
#include"Epoll.h"
#include"Thread.h"
#include<sys/timeb.h>
#include<stdarg.h>
#include <sys/stat.h>
#include "Server.h"

enum LogLevel
{
	LOG_INFO,
	LOG_DEBUG,
	LOG_WARNING,
	LOG_ERROR,
	LOG_FATAL
};

class LogInfo
{
public:
	LogInfo(const char* file, int line, const char* func, pid_t pid, pthread_t tid, int level, const char* fmt, ...);
	~LogInfo(){}
	operator Buffer()const { return m_buf; }
private:
	Buffer m_buf;
};

class CLogger
{
public:
	CLogger() :
		m_thread(&CLogger::ThreadFunc,this)
	{
		m_server = NULL;
		char curpath[256] = "";
		getcwd(curpath, sizeof(curpath));//获取当前工作路径
		m_path = curpath;
		m_path += "/log/" + GetTimerStr() + ".log";
	}
	~CLogger() { Close(); }
public:
	CLogger(const CLogger&) = delete;
	CLogger& operator=(const CLogger&) = delete;
public:
	int Start() {
		if (m_server != NULL)return -1;
		if (access("log", W_OK | R_OK)!=0) {//检查当前工作路径下有无log文件夹并且检查有无读写权限
			mkdir("log", S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
		}
		m_file = fopen(m_path, "w+");//此处若没有文件则创建文件，如有文件则每次都清空后从头写入，区别与"a+"
		if (m_file == NULL)return -2;//使用fopen必须要检查返回值，并且使用完成后要fclose
		int ret = m_epoll.Create(2);
		if (ret != 0)return -3;
		m_server = new CSocket();
		if (m_server == NULL) {
			Close();
			return -4;
		}
		ret = m_server->Init(CSocketParam("./log/server.sock", (int)(IS_SERVER | IS_REUSE)));
		if (ret != 0) {
			Close();
			return -5;
		}
		ret = m_epoll.Add(*m_server, EpollData((void*)m_server),EPOLLIN|EPOLLERR);//设置监听条件EPOLLIN 与 EPOLLERR，当有读操作或者错误时会触发该条件
		if (ret != 0) {
			Close();
			return -6;
		}
		ret = m_thread.Start();
		if (ret != 0) {
			Close();
			return -7;
		}
		return 0;
	}
	int Close(){
		if (m_server != NULL) {
			CSocket* p = m_server;
			m_server = NULL;
			delete p;
		}
		m_epoll.Close();
		m_thread.Stop();
		return 0;
	}
	static void Trace(const LogInfo& info) {
		static thread_local CSocket client;
		int ret = 0;
		if (client == -1) {
			ret = client.Init(CSocketParam("./log/server.sock", 0));
			if (ret != 0)return;
			ret = client.Link();
			if (ret != 0)
				printf("errno:%d msg:%s\n", errno, strerror(errno));
		}
		ret = client.Send(info);
		printf("%s(%d):[%s] ret=%d client = %d\n", __FILE__, __LINE__, __FUNCTION__, ret, (int)client);
	}

	static Buffer GetTimerStr() {
		Buffer result(128);
		timeb tb;
		ftime(&tb);
		tm* ptm = localtime(&tb.time);
		int nSize = snprintf(result, result.size(), "%04d-%02d-%02d_%02d-%02d-%02d.%03d",
			ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday,
			ptm->tm_hour, ptm->tm_min, ptm->tm_sec,
			tb.millitm);
		result.resize(nSize);
		return result;
	}
private:
	int ThreadFunc() {
		EPEVENTS events;
		std::map<int, CSocket*>m_mapclient;
		while ((m_epoll != -1) && (m_server != NULL) && m_thread.IsValid()) {
			ssize_t ret = m_epoll.WaitEvents(events,1000);
			if (ret < 0)break;
			if (ret > 0) {
				ssize_t i = 0;
				for (; i < ret; i++) {
					if (events[i].events & EPOLLERR) {
						break;
					}
					else if (events[i].events & EPOLLIN) {
						printf("%s(%d):<%s> pid=%d errno = %d msg = %s ret = %d\n", __FILE__, __LINE__, __FUNCTION__, getpid(), errno, strerror(errno), ret);
						if (events[i].data.ptr == m_server) {
							CSocket* pClient = NULL;
							int r = m_server->Link(&pClient);
							if (r < 0)continue;
							r = m_epoll.Add(*pClient, EpollData((void*)pClient), EPOLLIN | EPOLLERR);
							if (r < 0) {
								delete pClient;
								continue;
							}
							auto it = m_mapclient.find(*pClient);//此处是为了防止同一个socket被重复加入到epoll
							if (it != m_mapclient.end()) {
								if (it->second)delete it->second;//此处必须要判断it->second是否存在
							}
							m_mapclient[*pClient] = pClient;
						}
						else {
							CSocket* pClient = (CSocket*)events[i].data.ptr;
							if (pClient != NULL) {
								Buffer data(1024 * 1024);
								int r = pClient->Recv(data);
								if (r <= 0) {
									m_mapclient[*pClient] = NULL;
									delete pClient;
								}
								else {
									printf("%s(%d):[%s]data=%s \n", __FILE__, __LINE__, __FUNCTION__, (char*)data);
									WriteLog(data);
								}
							}
						}
					}
				}
				if (i != ret) {
					break;
				}
			}
		}
		for (auto it = m_mapclient.begin(); it != m_mapclient.end(); it++) {
			if (it->second) {//必须要判断it->second是否存在，不然可能会触发删除未知资源的错误
				delete it->second;
			}
		}
		m_mapclient.clear();
		return 0;
	}
	void WriteLog(const Buffer& data){
		printf("%s-%s[%d]\n", __FILE__, __FUNCTION__, __LINE__);
		if (m_file != NULL) {
			FILE* pFile = m_file;
			fwrite((char*)data, 1, data.size(), pFile);
			fflush(pFile);
		}
	}
private:
	CSocket* m_server;
	Epoll m_epoll;
	Thread m_thread;
	Buffer m_path;
	FILE* m_file;
};

#ifndef TRACE
#define TRACEI(...) CLogger::Trace(LogInfo(__FILE__,__LINE__,__FUNCTION__,getpid(),pthread_self(),LOG_INFO,__VA_ARGS__))
#define TRACED(...) CLogger::Trace(LogInfo(__FILE__,__LINE__,__FUNCTION__,getpid(),pthread_self(),LOG_DEBUG,__VA_ARGS__))
#define TRACEW(...) CLogger::Trace(LogInfo(__FILE__,__LINE__,__FUNCTION__,getpid(),pthread_self(),LOG_WARNING,__VA_ARGS__))
#define TRACEE(...) CLogger::Trace(LogInfo(__FILE__,__LINE__,__FUNCTION__,getpid(),pthread_self(),LOG_ERROR,__VA_ARGS__))
#define TRACEF(...) CLogger::Trace(LogInfo(__FILE__,__LINE__,__FUNCTION__,getpid(),pthread_self(),LOG_FATAL,__VA_ARGS__))
#endif